package com.spbl.common.utils;
import com.alibaba.fastjson.JSONObject;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTCreationException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.JWTVerifier;
import lombok.extern.slf4j.Slf4j;

import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * Description(jwt工具类)
 * 参考 https://github.com/auth0/java-jwt
 * author: Gao xueyong
 * Create at: 2020/5/27 9:42 下午
 */
@Slf4j
public class JwtUtils {
    /**
     * HMAC256
     * 签名字符串
     */
    public static final String SECRET = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9gxy";
    public static final String SUBJECT = "签名主题";

    public static final Long lifeTime = 60 * 60 * 1000L;
    //非对称密钥算法
    public static final String KEY_ALGORITHM="RSA";
    // 公钥
    public static  RSAPublicKey publicKey;
    // 私钥
    public static  RSAPrivateKey privateKey;

    /**
     * 密钥长度，DH算法的默认密钥长度是1024
     * 密钥长度必须是64的倍数，在512到65536位之间
     * */
    private static final int KEY_SIZE=1024;

    static {
        KeyPairGenerator keyPairGen = null;
        try {
            keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
        } catch (NoSuchAlgorithmException e) {
            log.error("初始化KeyPairGenerator失败！",e);
        }
        keyPairGen.initialize(KEY_SIZE);
        KeyPair keyPair = keyPairGen.generateKeyPair();
        // 公钥
        publicKey = (RSAPublicKey) keyPair.getPublic();
        // 私钥
        privateKey = (RSAPrivateKey) keyPair.getPrivate();
    }


    /**
     * 创建token
     *
     * @param userId   签名id
     * @return
     */
    public static String encryptHMAC256Token(String userId) {
        try {
            Date issuedAt = new Date();
            Algorithm algorithm = Algorithm.HMAC256(SECRET);
            Map<String,Object> claimMap = new HashMap<>();
            claimMap.put("userId",userId);
            claimMap.put("role","admin");
            String token = JWT.create()
//                    .withJWTId(userId)//签发id
                    .withSubject(SUBJECT)//主题
//                    .withIssuer(userName)//签发者
                    .withClaim("clainmInfo",claimMap)
                    .withIssuedAt(new Date())//签发时间
                    .withExpiresAt(new Date(issuedAt.getTime() + lifeTime))//token失效时间
                    .sign(algorithm);
            log.info("token={}", token);
            return token;
        } catch (JWTCreationException exception) {
            log.error("创建token失败！", exception);
        }
        return null;
    }

    /**
     * 创建token
     *
     * @param userId   签名id
     * @return
     */
    public static String encryptRSA256Token(String userId) {

        try {
            Date issuedAt = new Date();
            Algorithm algorithm = Algorithm.RSA256(publicKey, privateKey);
            Map<String,Object> claimMap = new HashMap<>();
            claimMap.put("userId",userId);
            claimMap.put("role","admin");
            String token = JWT.create()
//                    .withJWTId(userId)//签发id
                    .withSubject(SUBJECT)//主题
//                    .withIssuer(userName)//签发者
                    .withClaim("clainmInfo",claimMap)
                    .withIssuedAt(new Date())//签发时间
                    .withExpiresAt(new Date(issuedAt.getTime() + lifeTime))//token失效时间
                    .sign(algorithm);
            log.info("token={}", token);
            return token;
        } catch (JWTCreationException exception) {
            //Invalid Signing configuration / Couldn't convert Claims.
            log.error("创建token失败！", exception);
        }
        return null;
    }

    public static Map<String,Object> verifyHMAC256TokenMap(String token) {
        Map<String,Object> clainmInfoMap = null;
        try {
            Algorithm algorithm = Algorithm.HMAC256(SECRET);
            JWTVerifier verifier = JWT.require(algorithm)
//                    .withJWTId(userId)//签发id
                    .withSubject(SUBJECT)//主题
//                    .withIssuer(userName)//签发者
                    .build(); //Reusable verifier instance
            DecodedJWT jwt = verifier.verify(token);
            //自定义字段的获取
            Claim clainmInfo = jwt.getClaim("clainmInfo");
            clainmInfoMap = clainmInfo.asMap();
            log.info("clainmInfo = {}", JSONObject.toJSONString(clainmInfoMap));
            String header = jwt.getHeader();
            log.info("header = {}", header);
            String payload = jwt.getPayload();
            log.info("payload = {}", payload);
            String signature = jwt.getSignature();
            log.info("signature = {}", signature);
            String issuer = jwt.getIssuer();
            log.info("issuer = {}",issuer);
        } catch (JWTVerificationException exception) {
            //Invalid signature/claims
            log.error("解析token失败！", exception);
        }
        return clainmInfoMap;
    }

    public static Boolean verifyHMAC256Token(String token) {
        try {
            Algorithm algorithm = Algorithm.HMAC256(SECRET);
            JWTVerifier verifier = JWT.require(algorithm)
//                    .withJWTId(userId)//签发id
                    .withSubject(SUBJECT)//主题
//                    .withIssuer(userName)//签发者
                    .build(); //Reusable verifier instance
            DecodedJWT jwt = verifier.verify(token);
           return  true;
        } catch (JWTVerificationException exception) {
            //Invalid signature/claims
            log.error("解析token失败！", exception);
        }
        return false;
    }
    public static Map<String,Object> verifyRSA256TokenMap(String token) {
        Map<String,Object> clainmInfoMap = null;
        try {
            Algorithm algorithm = Algorithm.RSA256(publicKey, privateKey);
            JWTVerifier verifier = JWT.require(algorithm)
//                    .withJWTId(userId)//签发id
                    .withSubject(SUBJECT)//主题
//                    .withIssuer(userName)//签发者
                    .build(); //Reusable verifier instance
            DecodedJWT jwt = verifier.verify(token);
            //自定义字段的获取
            Claim clainmInfo = jwt.getClaim("clainmInfo");
            clainmInfoMap = clainmInfo.asMap();
            log.info("clainmInfo = {}", JSONObject.toJSONString(clainmInfoMap));
            String header = jwt.getHeader();
            log.info("header = {}", header);
            String payload = jwt.getPayload();
            log.info("payload = {}", payload);
            String signature = jwt.getSignature();
            log.info("signature = {}", signature);
            String issuer = jwt.getIssuer();
            log.info("issuer = {}",issuer);
        } catch (JWTVerificationException exception) {
            //Invalid signature/claims
            log.error("解析token失败！", exception);
        }
        return clainmInfoMap;
    }
    public static Boolean verifyRSA256Token(String token) {
        try {
            Algorithm algorithm = Algorithm.RSA256(publicKey, privateKey);
            JWTVerifier verifier = JWT.require(algorithm)
//                    .withJWTId(userId)//签发id
                    .withSubject(SUBJECT)//主题
//                    .withIssuer(userName)//签发者
                    .build(); //Reusable verifier instance
            DecodedJWT jwt = verifier.verify(token);
           return true;
        } catch (JWTVerificationException exception) {
            //Invalid signature/claims
            log.error("解析token失败！", exception);
        }
        return false;
    }

    public static void main(String[] args){
        String userId, userName, subject;
        userId = "1233";
        userName = "小明";
        subject = "jwt加密";

        userId = "xiaoming"+"123456";
        String token = encryptHMAC256Token(userId);
        verifyHMAC256Token(token);
        log.error("==================================================");
        token = encryptRSA256Token(userId);
        Boolean aBoolean = verifyRSA256Token(token);
        log.info("aBoolean={}",aBoolean);

    }
}
